package com.dkd.service.impl;

import cn.elegent.token.dto.RefreshDTO;
import cn.elegent.token.refresh.service.TokenService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dkd.config.constant.LoginType;
import com.dkd.dao.UserDao;
import com.dkd.dto.UserDTO;
import com.dkd.entity.UserEntity;
import com.dkd.http.vo.LoginReq;
import com.dkd.http.vo.LoginResp;
import com.dkd.service.PartnerService;
import com.dkd.service.UserService;
import com.dkd.sms.SmsSender;
import com.dkd.utils.BCrypt;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private PartnerService partnerService;
	
	@Autowired
	private SmsSender smsSender;
	
	@Autowired
	private TokenService tokenService;
	
	
	@Override
	public LoginResp login(LoginReq req) throws IOException {
		if (req.getLoginType() == LoginType.LOGIN_ADMIN.getCode()) {
			return this.adminLogin(req);
		} else if (req.getLoginType() == LoginType.LOGIN_EMP.getCode()) {
			return this.empLogin(req);
		} else if (req.getLoginType() == LoginType.LOGIN_PARTNER.getCode()) {
			return partnerService.login(req);
		}
		LoginResp resp = new LoginResp();
		resp.setSuccess(false);
		resp.setMsg("不存在该账户");
		
		return resp;
	}
	
	
	@Override
	public void sendCode(String mobile) {
		//非空校验
		if (Strings.isNullOrEmpty(mobile)) return;
		
		//查询用户表中是否存在该手机号
		LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
		wrapper
				.eq(UserEntity::getMobile, mobile);
		if (this.count(wrapper) <= 0) return;  //如果不存在，直接返回
		if (redisTemplate.opsForValue().get(mobile) != null) return;  //避免5分钟内重复发送
		//生成5位短信验证码
		StringBuilder sbCode = new StringBuilder();
		Stream.generate(() -> new Random().nextInt(10))
				.limit(5)
				.forEach(x -> sbCode.append(x));
		//将验证码放入redis  ，5分钟过期
		redisTemplate.opsForValue().set(mobile, sbCode.toString(), Duration.ofMinutes(5));
		log.info("短信验证码：" + sbCode);
		//发送短信
		smsSender.sendMsg(mobile, sbCode.toString());
	}
	
	/**
	 * 管理员登录
	 * @param req
	 * @return
	 * @throws IOException
	 */
	private LoginResp adminLogin(LoginReq req) throws IOException {
		LoginResp resp = new LoginResp();
		resp.setSuccess(false);
		String code = redisTemplate.boundValueOps(req.getClientToken()).get();
		if (Strings.isNullOrEmpty(code)) {
			resp.setMsg("验证码错误");
			return resp;
		}
		if (!req.getCode().equals(code)) {
			resp.setMsg("验证码错误");
			return resp;
		}
		QueryWrapper<UserEntity> qw = new QueryWrapper<>();
		qw.lambda()
				.eq(UserEntity::getLoginName, req.getLoginName());
		UserEntity userEntity = this.getOne(qw);
		if (userEntity == null) {
			resp.setMsg("账户名或密码错误");
			return resp;
		}
		boolean loginSuccess = BCrypt.checkpw(req.getPassword(), userEntity.getPassword());
		if (!loginSuccess) {
			resp.setMsg("账户名或密码错误");
			return resp;
		}
		return okResp(userEntity, LoginType.LOGIN_ADMIN);
	}
	
	
	/**
	 * 登录成功签发token
	 * @param userEntity
	 * @param loginType
	 * @return
	 */
	private LoginResp okResp(UserEntity userEntity, LoginType loginType) throws IOException {
		LoginResp resp = new LoginResp();
		resp.setSuccess(true);
		resp.setRoleCode(userEntity.getRoleCode());
		resp.setUserName(userEntity.getUserName());
		resp.setUserId(userEntity.getId());
		resp.setRegionId(userEntity.getRegionId() + "");
		resp.setMsg("登录成功");
		
		UserDTO userDTO = new UserDTO();
		userDTO.setUserId(userEntity.getId() + "");
		userDTO.setMobile(userEntity.getMobile());
		List<String> roles = new ArrayList<>();
		roles.add(loginType.getName());
		
		userDTO.setRoles(roles);
		RefreshDTO token = tokenService.createToken(userDTO); //生成token
		resp.setToken(token.getAccessToken().getToken());
		resp.setRefreshToken(token.getRefreshToken().getToken());
		resp.setTokenLifeTime(token.getAccessToken().getLifespan());
		resp.setRefreshLifeTime(token.getRefreshToken().getLifespan());
		return resp;
	}
	
	
	/**
	 * 运维运营人员登录
	 * @param req
	 * @return
	 * @throws IOException
	 */
	private LoginResp empLogin(LoginReq req) throws IOException {
		LoginResp resp = new LoginResp();
		resp.setSuccess(false);
		String code = redisTemplate.boundValueOps(req.getMobile()).get();
		if (Strings.isNullOrEmpty(code)) {
			resp.setMsg("验证码错误");
			return resp;
		}
		if (!req.getCode().equals(code)) {
			resp.setMsg("验证码错误");
			return resp;
		}
		
		QueryWrapper<UserEntity> qw = new QueryWrapper<>();
		qw.lambda()
				.eq(UserEntity::getMobile, req.getMobile());
		UserEntity userEntity = this.getOne(qw);
		if (userEntity == null) {
			resp.setMsg("不存在该账户");
			return resp;
		}
		return okResp(userEntity, LoginType.LOGIN_EMP);
	}
	
}
